#include "asynclogging.h"

#include <functional>
#include <utility>
#include <memory>

using namespace tiny_muduo;

void AsyncLogging::Append(const char* data,int len){
    MutexLockGuard guard(mutex_);
    if(current_->writeablebytes()>=len){
        current_->Append(data,len);
    }else{
        buffers_to_write.emplace_back(std::move(current_));
        if(next_){
            current_=std::move(next_);
        }else{
            current_.reset(new Buffer());
        }
        cond_.Notify();
    }
}

void AsyncLogging::Flush(){
    fflush(stdout);//fflush(stdout)意思是将缓冲区中的内容放入到标准输出中，缓冲区清空
}

void AsyncLogging::ThreadFunc(){
    latch_.CountDown();
    BufferPtr newbuffer_current(new Buffer());
    BufferPtr newbuffer_next(new Buffer());
    LogFilePtr log(new LogFile(filepath_));
    newbuffer_current->SetBufferZero();
    newbuffer_next->SetBufferZero();
    BufferVector buffers;

    /*
    双缓冲区技术涉及两个缓冲区：一个前台缓冲区（Front Buffer）和一个后台缓冲区（Back Buffer）。这两个缓冲区通常是内存中的两个连续空间，它们的大小和格式相同。
    当进行数据的显示或写入操作时，系统会交替使用这两个缓冲区。
    数据准备阶段：
    当需要更新显示内容时，系统会在后台缓冲区中进行所有的数据处理和渲染操作。前台缓冲区保持不变，继续显示当前的内容，确保用户看到的是连贯的图像或数据。
    数据交换阶段：
    一旦后台缓冲区的数据处理和渲染完成，系统会将后台缓冲区的内容快速复制到前台缓冲区。这个过程通常由硬件加速完成，非常迅速，因此用户几乎感觉不到任何延迟或卡顿。
    显示更新：
    复制完成后，系统会切换指针，使得下一个周期的数据处理在原来的前台缓冲区（现在是后台）进行，而新的前台缓冲区则显示刚刚复制的数据。
    */
    while(running_){
        MutexLockGuard guard(mutex_);
        if(buffers_to_write_.empty()){
            cond_.WaitFroFewSeconds(kBufferWriterTimeout);
        }

        buffers_to_write_.emplace_back(std::move(current_));
        buffers.swap(buffers_to_write_);
        current_=std::move(newbuffer_current);
        if(!next_){
            next_=std::move(newbuffer_next);
        }
    }

    for(const auto& buffer:buffers){
        log->Write(buffer->data(),buffer->len());
    }

    if(log->writtenbytes()>= kSingleFileMaximumSize){
        log.reset(new LogFile(filepath_));
    }

    if(buffers.size()>2){
        buffers.resize(2);
    }

    if(!newbuffer_current){
        newbuffer_current=std::move(buffers.back());
        buffers.pop_back();
        newbuffer_current->SetBufferZero();
    }

    if(!newbuffer_next){
        newbuffer_current=std::move(buffers.back());
        buffers.pop_back();
        newbuffer_current->SetBufferZero();
    }
    buffers.clear();
}